package com.example.security.config.component;

import cn.hutool.core.util.URLUtil;
import com.example.security.dto.Role;
import com.example.security.service.impl.RoleServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * 动态权限数据源
 * <p>
 * Created by devinlee on 2021.07.20
 */
@Component
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    // 全局保存所有资源路径与其对应的权限值
    private final static Map<String, ConfigAttribute> configAttributeMap = new HashMap<>();

    @Autowired
    private RoleServiceImpl roleService;

    @PostConstruct
    public void loadDataSource() {
        List<Role> roleList = roleService.list();
        for (Role role : roleList) {
            // 资源路径对应的权限值，如("/user/del","1:user:del")
            configAttributeMap.put(role.getUrl(), new org.springframework.security.access.SecurityConfig(role.getId() + ":" + role.getValue()));
        }
    }

    public void clearDataSource() {
        configAttributeMap.clear();
    }

    /**
     * 用户动态添加资源与权限值
     * @param url
     * @param configAttribute
     */
    public void addDataSource(String url, ConfigAttribute configAttribute){
        configAttributeMap.put(url, configAttribute);
    }

    /**
     * 用于动态移除资源与权限值
     * @param url
     */
    public void removeDataSource(String url){
        configAttributeMap.remove(url);
    }

    /**
     * 将请求的路径与所有系统路径匹配，返回该资源所需要的权限值
     * @param o
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        if (configAttributeMap == null) this.loadDataSource();
        List<ConfigAttribute> configAttributes = new ArrayList<>();
        //获取当前访问的路径
        String url = ((FilterInvocation) o).getRequestUrl();
        String path = URLUtil.getPath(url);
        PathMatcher pathMatcher = new AntPathMatcher();
        Iterator<String> iterator = configAttributeMap.keySet().iterator();
        //获取访问该路径所需资源
        while (iterator.hasNext()) {
            String pattern = iterator.next();
            if (pathMatcher.match(pattern, path)) {
                configAttributes.add(configAttributeMap.get(pattern));
            }
        }
        // 未设置操作请求权限，返回空集合
        return configAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }

}
